package com.sakila.action.member;

import javax.annotation.Resource;
import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.sakila.action.BaseAction;
import com.sakila.pojo.Member;
import com.sakila.service.CityService;
import com.sakila.service.MailService;
import com.sakila.service.MemberService;
import com.sakila.service.StoreService;
import com.sakila.vo.MyMember;

@Controller
public class MemberAction implements BaseAction{
	private static final Logger logger = LoggerFactory.getLogger(MemberAction.class);
	
	@Resource
	private StoreService storeService;
	@Resource
	private CityService cityService;
	@Resource
	private MemberService memberService;
	@Resource
	private MailService mailService;
	
	//page jumping
	
	@RequestMapping(value={"/member/", "/member/index"})
	public String memberIndexPage(){
		return "member/center";
	}
	
	@RequestMapping(value="/goto_register")
	public String viewRegister(Model model){
		this.setModelAndView(model, new Member());
		return "member/register";
	}
	
	@RequestMapping(value="/member/goto_modify")
	public String viewModify(Model model, Authentication au){
		MyMember myMember = (MyMember) au.getPrincipal();
		this.setModelAndView(model, myMember.getMember());
		return "member/modify";
	}
	
	@RequestMapping(value="/goto_resetPassword")
	public String dispatchResetPassword(){
		return "member/resetPwd";
	}
	//view data
	
	@RequestMapping(value="/member/viewOwn")
	@ResponseBody
	public Object viewOwnInfo(Authentication au){
		MyMember myMember = (MyMember) au.getPrincipal();
		return myMember.getMember();
	}
	
	@RequestMapping(value="/register", method=RequestMethod.POST)
	public String register(Model model, @Valid Member member, Errors errors){
		
		/**
		 *  validate password manually,
		 *  when edit member info, not input password means not to change password.
		 */
		if(member.getPassword() == null){
			logger.debug(">>>>>>>>>>>>>>>>register member: password is empty, add new error.");
			errors.rejectValue("password", "Not Null", "password should not be empty");
		}
		if(errors.hasErrors()){
			logger.debug(">>>>>>>>>>>>>>>>>Error occur: register new member");
			
			//Be careful, the request must contain the actual validated object not creating a new one.
			this.setModelAndView(model, member);
			return "member/register";
		}
		
		BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(16);
		String cryptedPwd = passwordEncoder.encode(new StringBuilder(member.getPassword()));
		member.setPassword(cryptedPwd);
		memberService.register(member);
		return "redirect:/member/login";
	}
	
	@RequestMapping(value="/member/modify", method=RequestMethod.POST)
	public String modify(Model model, @Valid Member member, Errors errors){
		if(errors.hasErrors()){
			logger.debug(">>>>>>>>>>>>>>>>>Error occur: modify member.");
			
			//Be careful, the request must contain the actual validated object not creating a new one.
			this.setModelAndView(model, member);
			return "member/modify";
		}
		
		boolean modifiedPassword = false;
		if(member.getPassword() != null){
			logger.debug(">>>>>>>>>>>>>>>>>Modify member: new password set.");
			BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(16);
			String cryptedPwd = passwordEncoder.encode(new StringBuilder(member.getPassword()));
			member.setPassword(cryptedPwd);
			modifiedPassword = true;
		}
		memberService.update(member);
		if(modifiedPassword){
			SecurityContextHolder.getContext().setAuthentication(null);
		}
		return "redirect:/member/";
	}
	
	@RequestMapping(value="/resetPassword", method=RequestMethod.POST)
	@ResponseBody
	public Object resetPassword(@RequestParam String username){
		return mailService.sendPasswordResetMail(username);
	}
	
	private void setModelAndView(Model model, Member member){
		model.addAttribute("member", member);
		model.addAttribute("stores", storeService.findAll());
		model.addAttribute("cities", cityService.findAll());
	}
}
